﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Windows.Forms;
using IWshRuntimeLibrary;
using WOLGateway.PresentationService;

namespace WOLGateway.ClientGUI
{
    /// <summary>
    /// WakeOnLanForm
    /// </summary>
    public partial class WakeOnLanForm : Form
    {
        #region Private member

        /// <summary>
        /// Automatically execute wakeup and close the application on success
        /// </summary>
        private bool autoExecuteAndClose = false;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="WakeOnLanForm"/> class.
        /// </summary>
        /// <param name="macAddress">MAC Address</param>
        /// <param name="wolGatewayServiceUrl">WOLGateway Service URL</param>
        public WakeOnLanForm(string macAddress, string wolGatewayServiceUrl)
        {
            InitializeComponent();

            Text += " - " + Assembly.GetExecutingAssembly().GetName().Version;

            checkBoxAutoClose.Checked = Properties.Settings.Default.AutoClose;

            if (string.IsNullOrEmpty(macAddress))
            {
                textBoxMacAddress.Text = Properties.Settings.Default.MacAddress;
            }
            else
            {
                textBoxMacAddress.Text = macAddress;
                checkBoxAutoClose.Checked = true;
                autoExecuteAndClose = true;
            }

            if (string.IsNullOrEmpty(wolGatewayServiceUrl))
            {
                textBoxWOLGatewayServiceUrl.Text = Properties.Settings.Default.WOLGatewayServerUrl;
            }
            else
            {
                textBoxWOLGatewayServiceUrl.Text = wolGatewayServiceUrl;
            }
        }

        #endregion

        #region Event processing

        /// <summary>
        /// Handles the click event of the wake up button.
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The parameter is not used.</param>
        private void OnClickButtonWakeUp(object sender, EventArgs e)
        {
            SendMagicPacketViaServer();
        }

        /// <summary>
        /// Send magic packet was completed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">EventArgs</param>
        private void OnSendMagicPacketToCompleted(object sender, StringEventArgs e)
        {
            var responseMessage = e.Text;
            if (!String.IsNullOrEmpty(responseMessage))
            {
                responseMessage = responseMessage.Trim();
                AsyncPerformInUIThread(() =>
                    {
                        buttonMessageDisplay.Text = responseMessage;
                        if (responseMessage.Length > 0)
                        {
                            if (!responseMessage.ToLower().Contains("error"))
                            {
                                buttonMessageDisplay.ForeColor = Color.Green;
                                buttonMessageDisplay.Refresh();

                                if (checkBoxAutoClose.Checked)
                                {
                                    if (Properties.Settings.Default.MacAddress == "00-00-00-00-00-00")
                                    {
                                        SaveCurrentOptions();
                                    }

                                    Environment.Exit(0);
                                }
                            }
                            else
                            {
                                buttonMessageDisplay.ForeColor = Color.Red;
                                buttonMessageDisplay.Refresh();
                            }
                        }

                        SetEnabledState(true);
                    });
            }
        }

        /// <summary>
        /// Send magic packet failed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">EventArgs</param>
        private void OnSendMagicPacketToFailed(object sender, StringEventArgs e)
        {
            AsyncPerformInUIThread(() =>
                    {
                        buttonMessageDisplay.Text = e.Text;
                        buttonMessageDisplay.ForeColor = Color.Red;
                        buttonMessageDisplay.Refresh();
                        SetEnabledState(true);
                    });
        }

        /// <summary>
        /// Handles the click event of the wake up button.
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The parameter is not used.</param>
        private void OnClickButtonSave(object sender, EventArgs e)
        {
            SaveCurrentOptions();
        }

        /// <summary>
        /// Handles the shown event of the form
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The parameter is not used.</param>
        private void OnShown(object sender, EventArgs e)
        {
            if (autoExecuteAndClose)
            {
                Application.DoEvents();
                SendMagicPacketViaServer();
            }
        }

        /// <summary>
        /// Handles the click event of the create desktop shortcut button.
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The parameter is not used.</param>
        private void OnClickButtonCreateDesktopShortcut(object sender, EventArgs e)
        {
            CreateDesktopShortcut();
        }

        /// <summary>
        /// Clicked on link
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The parameter is not used.</param>
        private void OnLinkClickedLinkLabelCodeplex(object sender, LinkLabelLinkClickedEventArgs e)
        {
            NavigateToCodeplex();
        }

        #endregion

        #region Private logic

        /// <summary>
        /// Create a desktop shortcut with the currently entered data
        /// </summary>
        private void CreateDesktopShortcut()
        {
            try
            {
                CreateShortcutOnDesktop("Wakeup" + " " + textBoxMacAddress.Text,
                    "Wake up the computer specified in the WOLGateway Client GUI",
                    "WOLGateway.ClientGUI.exe",
                    textBoxMacAddress.Text + " " + textBoxWOLGatewayServiceUrl.Text);
            }
            catch (Exception ex)
            {
                buttonMessageDisplay.Text = "Error creating shortcuts: " + ex.Message;
                buttonMessageDisplay.ForeColor = Color.Red;
                buttonMessageDisplay.Refresh();
            }
        }

        /// <summary>
        /// Send magic packet via server
        /// </summary>
        private void SendMagicPacketViaServer()
        {
            buttonMessageDisplay.ForeColor = Color.Black;
            buttonMessageDisplay.Text = string.Empty;
            buttonMessageDisplay.Refresh();
            try
            {
                SetEnabledState(false);
                buttonMessageDisplay.Text = "Sending magic packet for wakeup, please wait...";
                buttonMessageDisplay.Refresh();

                var proxy = new Proxy(textBoxWOLGatewayServiceUrl.Text, Properties.Settings.Default.IgnoreServerCertificateValidation);
                proxy.OnSendMagicPacketToCompleted += OnSendMagicPacketToCompleted;
                proxy.OnSendMagicPacketToFailed += OnSendMagicPacketToFailed;
                proxy.BeginSendMagicPacketTo(textBoxMacAddress.Text);
            }
            catch (Exception ex)
            {
                buttonMessageDisplay.Text = "Client Error: " + ex.Message;
                buttonMessageDisplay.ForeColor = Color.Red;
                buttonMessageDisplay.Refresh();
                SetEnabledState(true);
            }
        }

        /// <summary>
        /// Sets the enabled state of all input fields and buttons during the wakeup action.
        /// </summary>
        /// <param name="enabled">True, if enabled</param>
        private void SetEnabledState(bool enabled)
        {
            textBoxWOLGatewayServiceUrl.Enabled = enabled;
            textBoxMacAddress.Enabled = enabled;
            checkBoxAutoClose.Enabled = enabled;
            buttonSave.Enabled = enabled;
            buttonCreateDesktopShortcut.Enabled = enabled;
            buttonWakeUp.Enabled = enabled;
        }

        /// <summary>
        /// Save the current options.
        /// </summary>
        private void SaveCurrentOptions()
        {
            Properties.Settings.Default.MacAddress = textBoxMacAddress.Text;
            Properties.Settings.Default.WOLGatewayServerUrl = textBoxWOLGatewayServiceUrl.Text;
            Properties.Settings.Default.AutoClose = checkBoxAutoClose.Checked;
            Properties.Settings.Default.Save();
        }

        /// <summary>
        /// Navigate to CodePlex project page.
        /// </summary>
        private void NavigateToCodeplex()
        {
            try
            {
                ProcessStartInfo processStartInfo = new ProcessStartInfo("http://wolgateway.codeplex.com");
                Process.Start(processStartInfo);
            }
            catch (Exception ex)
            {
                MessageBox.Show(String.Format("Error message from operating system:{0}{1}", Environment.NewLine, ex.Message));
            }
        }

        #endregion

        #region Helper methods

        /// <summary>
        /// Perform the given action in the context of the UI Thread
        /// </summary>
        /// <param name="action">Action to be performed</param>
        private void AsyncPerformInUIThread(Action action)
        {
            if (InvokeRequired)
            {
                var result = BeginInvoke((MethodInvoker)(() => AsyncPerformInUIThread(action)));
                return;
            }

            action();
        }

        /// <summary>
        /// Creates a desktop shortcut
        /// </summary>
        /// <param name="filename">The filename of the shortcut on the desktop</param>
        /// <param name="description">Shortcut description</param>
        /// <param name="target">The target (EXE) file for the shortcut</param>
        /// <param name="args">Arguments</param>
        /// <param name="shortcutKeys">Shortcut keys</param>
        private void CreateShortcutOnDesktop(string filename, string description, string target, string args, string shortcutKeys = "")
        {
            object desktopReference = (object)"Desktop";
            WshShell shell = new WshShell();
            string shortcutAddress = Path.Combine((string)shell.SpecialFolders.Item(ref desktopReference), filename);
            IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutAddress + ".lnk");
            shortcut.Description = description;
            if (!string.IsNullOrEmpty(shortcutKeys))
            {
                shortcut.Hotkey = shortcutKeys;
            }

            shortcut.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory;
            shortcut.TargetPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, target);
            shortcut.Arguments = args;
            shortcut.Save();
        }

        #endregion
    }
}